/*
 *  testKernelCondition.c
 *  
 *  Tests the use of kernel condition variables.
 *
 */

#include "syscall.h"

int testCV;
int testLock;

/* Takes in a char array and returns the length of the char array. */
int charCount(char* ch)
{
	int count = 0;
	int i=0;
	while(ch[i] != '\n')
	{
		count++;
		i++;
	}
	return count+1;
}

/* Test 1: Normative scenario. Thread 1 will acquire a lock then wait on the lock.
 * Thread 2 will try to acquire. When thread 2 acquires he will signal and call exit.
 * Thread 1 will resume then call exit.
 */
int test1lock;
int test1cv;
void test1_t1()
{
	int n=0;
	LockAcquire(testLock);
	LockAcquire(test1lock);
	Write("Thread 1 is waiting for Test1CV\n", charCount("Thread 1 is waiting for Test1CV\n"), ConsoleOutput);
	CVWait(test1cv, test1lock);
	/* signal the main thread that test 1 is done */
	Write("Thread 1 is now awake.\n", charCount("Thread 1 is now awake.\n"), ConsoleOutput);
	LockRelease(test1lock);
	CVSignal(testCV, testLock);
	LockRelease(testLock);
	Exit(0);
}

void test1_t2()
{
	int n=0;
	for(n=0; n<100;n++);
	LockAcquire(test1lock);
	Write("Thread 2 working in critical section.\n", charCount("Thread 2 working in critical section.\n"), ConsoleOutput);
	for(n=0; n<1000; n++);
	Write("Thread 2 finished working in the critical section.\n", charCount("Thread 2 finished working in the critical section.\n"), ConsoleOutput);
	CVSignal(test1cv, test1lock);
	LockRelease(test1lock);
	Exit(0);
}

/* Test 2: Try to destroy too early. Thread 1 acquires the lock and works in the critical section. 
 * Then the thread tries to destroy the CV. In the meantime Thead 2 was waiting on the CV so Thread
 * 1's attempt to destroy will fail but just mark it to be deleted. Test2 cv is then signalled so 
 * thread 2 will now gain control of the critical section and then signal to the main thread that
 * the test is done.
 */
int test2lock;
int test2cv;
void test2_t1()
{
	int p=0;
	LockAcquire(test2lock);
	Write("Working in critical section\n", charCount("Working in critical section\n"), ConsoleOutput);
	for(p=0;p<100;p++); 
	/*CVSignal(testCV, testLock);*/
	CVDestroy(test2cv);
	CVSignal(test2cv, test2lock);
	LockRelease(test2lock);
	Exit(0);
}

void test2_t2()
{
	LockAcquire(testLock);
	
	LockAcquire(test2lock);
	Write("Waiting for test2cv\n", charCount("Waiting for test2cv\n"), ConsoleOutput);
	/*CVWait(testCV, testLock);*/
	CVWait(test2cv, test2lock);
	Write("Releasing test2lock. Signal that test 2 is done.\n", charCount("Releasing test2lock. Signal that test 2 is done.\n"), ConsoleOutput);
	LockRelease(test2lock);
	CVSignal(testCV, testLock);
	LockRelease(testLock);
	Exit(0);
}

/* Test 3: Try to access CVs that are out of range. */
int test3lock;
int test3cv;
void test3_t1()
{
	LockAcquire(testLock);
	LockAcquire(test3lock);
	Write("Thread 1 is now waiting\n", charCount("Thread 1 is now waiting\n"), ConsoleOutput);
	CVWait(test3cv, test3lock);
	Write("Thread 1 is signalling to main that the test is done.\n", charCount("Thread 1 is signalling to main that the test is done.\n"), ConsoleOutput);
	CVSignal(testCV, testLock);
	LockRelease(test3lock);
	LockRelease(testLock);
	Exit(0);
}

void test3_t2()
{
	int i=0;
	for(i=0;i<100;i++);
	LockAcquire(test3lock);
	Write("Thread 2 is now going to try to signal some bogus CV values\n", charCount("Thread 2 is now going to try to signal some bogus CV values\n"), ConsoleOutput);
	CVSignal(10000, 10000);
	CVSignal(-100,-100);
	Write("Thread 2 is now going to signal back to Thread 1 with correct value\n", charCount("Thread 2 is not going to signal back to Thread 1 with correct value\n"), ConsoleOutput);
	CVSignal(test3cv, test3lock);
	LockRelease(test3lock);
	Exit(0);
}

/* Test 4: Create the maximum amout of condition variables. */
void test4_t1()
{
	int n=0;
	int arrOfCVs[30];
	LockAcquire(testLock);
	Write("Test4 Thread 1 creating 60 condition variables. (NOTE: there is one condition var that controls this test so there are only 59 open spots for CVs)\n",
		  charCount("Test4 Thread 1 creating 60 condition variables. (NOTE: there is one condition var that controls this test so there are only 59 open spots for CVs)\n"),
		  ConsoleOutput);
	for(n=0;n<60;n++)
	{
		arrOfCVs[n] = CreateCV("test4cv", charCount("test4cv"));
	}
	Write("Now destroying the 59 condition variables that were created.\n", 
		  charCount("Now destroying the 59 condition variables that were created.\n"), 
		  ConsoleOutput);
	for(n=0;n<59;n++)
	{
		CVDestroy(arrOfCVs[n]);
	}
	CVSignal(testCV, testLock);
	LockRelease(testLock);
	Exit(0);
}

/* Test 5: Will attemp to give the CV bad char arrays */
void test5_t1()
{
	char* name1 = ((char*) 0);
	LockAcquire(testLock);
	Write("Giving char arrays that point to bad values/null space\n", charCount("Giving char arrays that point to bad values/null space\n"), ConsoleOutput);
	CreateCV(name1, 0);
	CreateCV(name1, -1);
	CreateCV(name1, 2000);
	CVSignal(testCV, testLock);
	LockRelease(testLock);
	Exit(0);
}


int main()
{
	testCV = CreateCV("Kernel Condition Test CV", 24);
	testLock = CreateLock("Kernel Condition Test Lock", 26);
	/* Begin test 1 then wait for the testCV to be signalled to go to next test */
	Write("*** Begin test 1 ***\n", charCount("*** Begin test 1 ***\n"), ConsoleOutput);
	test1lock = CreateLock("test1 lock", charCount("test1 lock"));
	test1cv = CreateCV("test1 cv", charCount("test1 cv"));
	Fork(&test1_t1, "Test1_T1", 8);
	Fork(&test1_t2, "Test1_T2", 8);
	CVWait(testCV, testLock);
	LockDestroy(test1lock);
	CVDestroy(test1cv);
	Write("*** Test 1 Finished ***\n\n", charCount("*** Test 1 Finished ***\n\n"), ConsoleOutput);
	/* Done with test 1 */
	
	Write("*** Begin test 2 ***\n", charCount("*** Begin test 2 ***\n"), ConsoleOutput);
	test2lock = CreateLock("test2 lock", charCount("test2 lock"));
	test2cv = CreateCV("test2 cv", charCount("test2 cv"));
	Fork(&test2_t2, "Test2_T2",8);
	Fork(&test2_t1, "Test2_T1",8);
	CVWait(testCV, testLock);
	LockDestroy(test2lock);
	Write("*** Test 2 Finished ***\n\n", charCount("*** Test 2 Finished ***\n\n"), ConsoleOutput);
	/* Done with test 2 */
	
	Write("*** Begin test 3 ***\n", charCount("*** Begin test 3 ***\n"), ConsoleOutput);
	test3lock = CreateLock("test3 lock", charCount("test3 lock"));
	test3cv = CreateCV("test3 cv", charCount("test3 cv"));
	Fork(&test3_t1, "Test3_T1",8);
	Fork(&test3_t2, "Test3_T2",8);
	CVWait(testCV, testLock);
	LockDestroy(test3lock);
	CVDestroy(test3cv);
	Write("*** Test 3 Finished ***\n\n", charCount("*** Test 3 Finished ***\n\n"), ConsoleOutput);
	/* Done with test 3 */
	
	Write("*** Begin test 4 ***\n", charCount("*** Begin test 4 ***\n"), ConsoleOutput);
	Fork(&test4_t1, "Test4_T1", 8);
	CVWait(testCV,testLock);
	Write("*** Test 4 Finished ***\n\n", charCount("*** Test 4 Finished ***\n\n"), ConsoleOutput);
	/* Done with test 4 */
	
	Write("*** Begin test 5 ***\n", charCount("*** Begin test 5 ***\n"), ConsoleOutput);
	Fork(&test5_t1, "Test5_T1", 8);
	CVWait(testCV,testLock);
	Write("*** Test 5 Finished ***\n\n", charCount("*** Test 5 Finished ***\n\n"), ConsoleOutput);
	/* Done with test 5 */
	
	LockRelease(testLock);
	LockDestroy(testLock);
	CVDestroy(testCV);
	Exit(0);
}

